Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support force cache even when server doesn't set the Date header #6175

Merged

Conversation

c2zwdjnlcg
Copy link
Contributor

This fixes a bug where when a upstream server doesn't set a Date header the response will be cached but then once the cache is expired it never gets refreshed because parseResponseHeaders returns a no date header error

This also makes it so that the force_cache_duration_seconds is respected when an upstream returns a 304 not modified

@c2zwdjnlcg c2zwdjnlcg force-pushed the force-cache-refresh branch 2 times, most recently from 218979d to 9b10ddd Compare August 22, 2023 23:33
@ashutosh-narkar
Copy link
Member

@c2zwdjnlcg thanks for looking into this. It would be great if you could clarify this behavior and point to any resources/ rfc that explain this. I would have imagined that the server should set the necessary headers.

On the forced cache 304 scenario, that could be a valid issue. Some tests would be helpful for both. Thanks!

@c2zwdjnlcg
Copy link
Contributor Author

Unfortunately not all servers set Date headers. The RFC says the the date header is required unless the server doesn't have a valid clock

If the server does not have a clock that can provide a reasonable approximation of the current time, its responses MUST NOT include a Date header field. In this case, the rules in section 14.18.1 MUST be followed.

But beyond that, it's just a fact of life that not all servers generate a date header. Either way though here the current behavior is problematic, the first time the call gets made the request is successful and cached but once it expires, it can never be refreshed and can never be cleared. My thinking is that since forced really doesn't require all these headers, ignoring these headers is the right thing to do. This was the behavior in older versions of OPA (< 0.46). Though there were other cache related bugs there as well.

Where do you suggest I add tests? Is http_test.go the right place?

topdown/http.go Outdated
@@ -841,7 +841,11 @@ func (c *interQueryCache) checkHTTPSendInterQueryCache() (ast.Value, error) {

headers, err := parseResponseHeaders(cachedRespData.Headers)
if err != nil {
return nil, err
if forceCaching(c.forceCacheParams) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseResponseHeaders parses at the etag value as well for instance which is needed in the revalidation server request. So we still need that even if the parsing of the time/date related headers gives an error.

Copy link
Contributor Author

@c2zwdjnlcg c2zwdjnlcg Aug 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm sort of assuming here that if a server isn't going to support dates it's not going to support etags either. But maybe that's a wrong assumption. What would you suggest here? Should I split up the date and etag processing so that one can succeed without the other? Or should I just make parseResponseHeaders less strict so that it doesn't throw errors but just ignores missing or malformed headers, maybe with a log message?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the only values needed are etag and last-modified. Let's see what parseResponseHeaders is doing and if the values it's parsing are actually used anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I confirmed that parseResponseHeaders is only used with revalidateCachedResponse which only looks at etagand last-modified both of which can be parsed without potential errors. I've made that change to this PR. See what you think.

@ashutosh-narkar
Copy link
Member

Where do you suggest I add tests? Is http_test.go the right place?

Yes.

@c2zwdjnlcg
Copy link
Contributor Author

c2zwdjnlcg commented Aug 23, 2023

Added some tests

@netlify
Copy link

netlify bot commented Aug 23, 2023

Deploy Preview for openpolicyagent ready!

Name Link
🔨 Latest commit 029419d
🔍 Latest deploy log https://app.netlify.com/sites/openpolicyagent/deploys/64e68fd0f8e9f10008bc709c
😎 Deploy Preview https://deploy-preview-6175--openpolicyagent.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link
Member

@ashutosh-narkar ashutosh-narkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes look good. Just one small comment.

if ast.String(tc.response).Compare(resResponse.Value) != 0 {
t.Fatalf("Expected response on query %d to be %v, got %v", i, tc.response, resResponse.String())
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea behind the logic below seems to simulate an expired cache entry and hence trigger the revalidation logic for the forced cache case. It would be be helpful to add a note about this for reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments

@c2zwdjnlcg
Copy link
Contributor Author

Test failure seems unrelated, but i can't reproduce locally.

@ashutosh-narkar
Copy link
Member

Test failure seems unrelated, but i can't reproduce locally.

Yeah they're unrelated to your changes.

Copy link
Member

@ashutosh-narkar ashutosh-narkar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

This fixes a bug where when a upstream server doesn't set a Date
header the response will be cached but then once the cache is
expired it never gets refreshed because parseResponseHeaders
returns a no date header error

This also makes it so that the force_cache_duration_seconds
is respected when an upstream returns a 304 not modified

Signed-off-by: Peter <[email protected]>
@ashutosh-narkar ashutosh-narkar merged commit 8dcdd7d into open-policy-agent:main Aug 25, 2023
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants